home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Games Collection 1 / software vault.zip / software vault / CDR10 / ACK3D.ZIP / DEMO / DEMO.C < prev    next >
Text File  |  1993-08-24  |  60KB  |  2,660 lines

  1. /*********************( Animation Construction Kit Demo )**********************/
  2. /*                Lary Myers                      */
  3. /*                                          */
  4. /*  Okay, don't laugh, this program started out to be a tutorial on using the */
  5. /* functions in the ACK3D library but then grew and grew, and grew! Now it's  */
  6. /* a coalage of routines, experiments, half-wit ideas, etc. I think what I    */
  7. /* wanted to do was see if the engine itself could be used in a large scale   */
  8. /* game. While Station Escape doesn't come close to commercial (or even       */
  9. /* shareware) quality, it does demonstrate that the engine can be used to     */
  10. /* produce something other than quick demo's. You are welcome to hack away    */
  11. /* at this code, or toss it completely and start anew. I'm putting this into  */
  12. /* the public domain "as-is" for everyone to share. Maybe it will spark some  */
  13. /* ideas for other games that then go on to be BIG sellers! If so, then I     */
  14. /* will be pleased to know that I helped in some way towards new games.          */
  15. /*                                          */
  16. /* Thank You for looking at the ACK demonstration and engine.              */
  17. /*                                          */
  18. /* Lary Myers CIS account 72355,655                          */
  19. /*****************************<      ACK-3D   >***********************************/
  20. #include <stdlib.h>
  21. #include <stdio.h>
  22. #include <dos.h>
  23. #include <mem.h>
  24. #include <alloc.h>
  25. #include <io.h>
  26. #include <fcntl.h>
  27. #include <time.h>
  28. #include <string.h>
  29. #include <conio.h>
  30. #include <ctype.h>
  31. #include <sys\stat.h>
  32. #include "ack3d.h"
  33. #include "acksnd.h"
  34. #include "demo.h"
  35.  
  36. /* Variables in the DEMORD.C module */
  37. extern        char        GridFile[];
  38. extern        char        PalFile[];
  39. extern        int            ErrorCode;
  40.  
  41.  
  42. /****** G L O B A L S ******************************/
  43.         ACKENG        *ae;        /* The main interface struct */
  44.         MOUSE        mouse;
  45.         UCHAR        scanCode;
  46.         UCHAR        Keys[128];
  47.         int            HaveMouse;
  48.         int            SoundDevice;    /* Selected from command line */
  49.         int            Shooting;
  50.         int            BoltEnergy;
  51.         int            Decompress;
  52.         int            MouseMode;    /* 0 = UW2 style, 1 = Wolf style */
  53.         int            LockedFlag;
  54.         int            TotalInventory;
  55.         int            InventoryFlag;
  56.         int            HoloSoundFlag;
  57.         int            YouWON;
  58.         VIEWERS        Views[] = {
  59.                  96,96,INT_ANGLE_90,
  60.                  96,96,0,
  61.                  96,96,INT_ANGLE_90
  62.                  };
  63.  
  64.         void        interrupt (*oldvec)();
  65.         void        interrupt myInt();
  66.  
  67.         void        interrupt (*OldTimer)();
  68.         void        interrupt MyTimer();
  69.  
  70.  
  71.         UCHAR        nums[] = {1,2,3,4,5,6,7,8};
  72.         UCHAR        snums[] = {17,17,18,18,19,19,20,20,20,20,
  73.                        19,19,18,18,17,17,17,17,17,17,
  74.                        17,17,17,17,17,17,17,17};
  75.         UCHAR        bnums[] = {9,9,9,10,10,11,12,13,14,15,16,
  76.                        11,10,9,9,9,9,9,9,9,9,9,9,9,
  77.                        9,9,9,9,9,9,9,9,9,9,9,9,9,9};
  78.  
  79.         char        Path[] = "bitmaps\\";
  80.         UINT        VidOffset;
  81.  
  82.         char        tmHours;
  83.         char        tmMinutes;
  84.         char        tmSeconds;
  85.         int            tmDelay;
  86.         int            tmCounter;
  87.         int            LastMouseIndex;
  88.  
  89.         int            OldWall;
  90.         int            NewWall;
  91.         int            WallDelay;
  92.         UCHAR        WallType[] = {2,3,4};
  93.         UCHAR        WallType1[] = {11,12,13,14};
  94.         UCHAR        WallType2[] = {7,8};
  95.         UCHAR        WallType3[] = {9,10};
  96.         UCHAR        WallType4[] = {28,29};
  97.  
  98.         UCHAR        HoloWalls[] = {41,44,45,45};
  99.  
  100.         UCHAR        Inventory[MAX_INVENTORY+1];
  101.  
  102.         int            SpaceMenDelay[21];
  103.  
  104.         int            WallIndex;
  105.         int            WallIndex1;
  106.         int            WallIndex2;
  107.         int            WallIndex3;
  108.         int            WallIndex4;
  109.         int            HoloIndex;
  110.         UCHAR       far    *wMaps[3];
  111.         UCHAR       far    *wMaps1[4];
  112.         UCHAR       far    *wMaps2[2];
  113.         UCHAR       far    *wMaps3[2];
  114.         UCHAR       far    *wMaps4[2];
  115.  
  116.         UCHAR       far    *hMaps[4];
  117.  
  118. /***** Mouse cursor bitmaps ******/
  119.         unsigned        Arrow[32] = {
  120.                  0x3fff,0x1fff,0xfff,0x7ff,0x3ff,0x1ff,0xff,0x7f,
  121.                  0x3f,0x1f,0xf,0x7,0x1847,0x387f,0xfc3f,0xfe7f,
  122.                  0x0,0x4000,0x6000,0x7000,0x7800,0x7c00,0x7e00,0x7f00,
  123.                  0x7f80,0x7fc0,0x7fe0,0x6730,0x4300,0x300,0x180,0x0};
  124.  
  125.  
  126.         unsigned        UpArrow[32] = {
  127.                  0xfeff,0xfc7f,0xf83f,0xf01f,0xe00f,0xc007,0xc007,0xc007,
  128.                  0xc007,0xc827,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,
  129.                  0x0,0x100,0x380,0x7c0,0xfe0,0x1ff0,0x1ff0,0x1bb0,
  130.                  0x1390,0x380,0x380,0x380,0x380,0x380,0x380,0x0};
  131.  
  132.         unsigned        DownArrow[32] = {
  133.                  0xffff,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xc827,
  134.                  0xc007,0xc007,0xc007,0xe00f,0xf01f,0xf83f,0xfc7f,0xfeff,
  135.                  0x0,0x0,0x380,0x380,0x380,0x380,0x380,0x380,
  136.                  0x1390,0x1bb0,0x1ff0,0xfe0,0x7c0,0x380,0x100,0x0};
  137.  
  138.         unsigned        LeftArrow[32] = {
  139.                  0xffff,0xf7ff,0xe3ff,0xc0ff,0x807f,0x3f,0x801f,0xc01f,
  140.                  0xe01f,0xf41f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,0xfc1f,
  141.                  0x0,0x0,0x800,0x1800,0x3f00,0x7f80,0x3fc0,0x19c0,
  142.                  0x9c0,0x1c0,0x1c0,0x1c0,0x1c0,0x1c0,0x1c0,0x0};
  143.  
  144.         unsigned        RightArrow[32] = {
  145.                  0xffff,0xffef,0xffc7,0xff03,0xfe01,0xfc00,0xf801,0xf803,
  146.                  0xf807,0xf82f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,0xf83f,
  147.                  0x0,0x0,0x10,0x18,0xfc,0x1fe,0x3fc,0x398,
  148.                  0x390,0x380,0x380,0x380,0x380,0x380,0x380,0x0};
  149.  
  150.         MCURSORS        mCursors[] = {
  151.                  1,0,Arrow,
  152.                  7,0,UpArrow,
  153.                  7,15,DownArrow,
  154.                  0,5,LeftArrow,
  155.                  7,5,RightArrow
  156.                  };
  157.  
  158.  
  159.         char        far *SoundFiles[SOUND_MAX_INDEX+1];
  160.  
  161.         char        MusicFile[60];
  162.  
  163.         UCHAR        FontTransparent;
  164.         UCHAR        FontColor;
  165.         UCHAR        TextBGcolor;
  166.         UCHAR        far *smFont;
  167.         UCHAR        far *CompassBmp;
  168.  
  169.  
  170.         char        *ObjectText[] = {
  171.                 "Circuit Board....",
  172.                 "Fuel Cells.......",
  173.                 "Computer........."
  174.                 };
  175.  
  176.         char        ObjectList[OBJECT_COUNT+1];
  177.  
  178.  
  179.         HOLOTEXT        HoloText[] = {
  180.                 HT_TEXTX,HT_TEXTY,"No program",
  181.                 HT_TEXTX,HT_TEXTY+10,"Program 1",
  182.                 HT_TEXTX,HT_TEXTY+20,"Program 2",
  183.                 -1,-1,0
  184.                 };
  185.  
  186.  
  187.  
  188. /****************************************************************************
  189. ** Here we load a specific DP2 brush that we'll use as our display font.   **
  190. **                                       **
  191. ****************************************************************************/
  192. int LoadSmallFont(void)
  193. {
  194.     int        ht,wt,len;
  195.  
  196. smFont = AckReadiff("bitmaps\\spfont.bbm");
  197. if (smFont == NULL)
  198.     return(-1);
  199.  
  200. ht = (*(int *)smFont);
  201. wt = (*(int *)&smFont[2]);
  202. len = ht * wt;
  203. memmove(smFont,&smFont[4],len);
  204.  
  205. return(0);
  206. }
  207.  
  208. /****************************************************************************
  209. ** Displays a character either directly on the video, or into the screen   **
  210. ** buffer depending on whether FontTransparent flag is set.           **
  211. **                                       **
  212. ****************************************************************************/
  213. void smWriteChar(int x,int y,unsigned char ch)
  214. {
  215.         int     FontOffset,VidOffset;
  216.         int     row,col;
  217.     unsigned    char far *Video;
  218.  
  219. VidOffset = (y * 320) + x;
  220. Video = MK_FP(0xA000,VidOffset);
  221.  
  222. FontOffset = ((ch-32) * 5);
  223.  
  224. if (FontTransparent)
  225.     Video = ae->ScreenBuffer + VidOffset;
  226.  
  227. for (row = 0; row < 5; row++)
  228.     {
  229.     if (!FontTransparent)
  230.     memset(Video,TextBGcolor,4);
  231.  
  232.     if (smFont[FontOffset])
  233.     Video[0] = FontColor;
  234.     if (smFont[FontOffset+1])
  235.     Video[1] = FontColor;
  236.     if (smFont[FontOffset+2])
  237.     Video[2] = FontColor;
  238.     if (smFont[FontOffset+3])
  239.     Video[3] = FontColor;
  240.  
  241.     Video += 320;
  242.     FontOffset += 294;
  243.     }
  244.  
  245.  
  246. }
  247.  
  248. /****************************************************************************
  249. ** Calls smWriteChar() to display the contents of the passed string. Only  **
  250. ** crude string handling is done in this routine.               **
  251. **                                       **
  252. ****************************************************************************/
  253. int smWriteString(int x,int y,char *s)
  254. {
  255.     int        OrgX;
  256.     char    ch;
  257.  
  258. OrgX = x;
  259.  
  260. mouse_hide_cursor();
  261. while (*s)
  262.     {
  263.     ch = *s++;
  264.  
  265.     if (ch == 10)    /* If a linefeed then advance to next row */
  266.     {
  267.     x = OrgX;
  268.     y += 8;
  269.     continue;
  270.     }
  271.  
  272.     if (ch < ' ')
  273.     continue;
  274.  
  275.     ch = toupper(ch);
  276.     smWriteChar(x,y,ch);
  277.     x += 5;        /* Advance to next character position */
  278.     }
  279. mouse_show_cursor();
  280.  
  281. return(y);
  282. }
  283.  
  284. /****************************************************************************
  285. ** Sets the transparent flag and then calls smWriteString() to place the   **
  286. ** string into the system buffer. This routine is called after the walls   **
  287. ** are drawn so the text appears to float on top of the walls.           **
  288. ****************************************************************************/
  289. void smWriteHUD(int x,int y,UCHAR color,char *s)
  290. {
  291. FontTransparent = 1;
  292. FontColor = color;
  293. smWriteString(x,y,s);
  294. FontTransparent = 0;
  295. FontColor = 15;
  296. }
  297.  
  298. /****************************************************************************
  299. ** Just a quick menu pick list to allow the player to select the desired   **
  300. ** holodeck program to run.                           **
  301. **                                       **
  302. ****************************************************************************/
  303. int PickHoloProgram(void)
  304. {
  305.     int    i,mx,my,mbutton;
  306.     int    prognum,x,x1,y;
  307.     UCHAR    hColor;
  308.  
  309. mouse_hide_cursor();
  310. hColor = 14;
  311. i = 0;
  312. while (1)
  313.     {
  314.     if (HoloText[i].x == -1)
  315.     break;
  316.     smWriteHUD(HoloText[i].x,HoloText[i].y,hColor,HoloText[i].Text);
  317.     i++;
  318.     }
  319.  
  320. AckDisplayScreen(ae);
  321.  
  322. mouse_show_cursor();
  323. if (MouseMode)
  324.     mouse_show_cursor();
  325.  
  326. prognum = -2;
  327.  
  328. while (prognum == -2)
  329.     {
  330.     mouse_read_cursor(&mbutton,&my,&mx);
  331.  
  332.     if (mbutton & 2)
  333.     {
  334.     prognum = -1;
  335.     break;
  336.     }
  337.  
  338.     if (mbutton & 1)
  339.     {
  340.     i = 0;
  341.     while (1)
  342.         {
  343.         x = HoloText[i].x;
  344.         if (x == -1)
  345.         break;
  346.  
  347.         y = HoloText[i].y;
  348.         x1 = (strlen(HoloText[i].Text) * 5) + x;
  349.  
  350.         if (mx >= x && mx <= x1 && my >= y && my <= (y+5))
  351.         {
  352.         prognum = i;
  353.         break;
  354.         }
  355.         i++;
  356.         }
  357.     }
  358.     }
  359.  
  360. if (MouseMode)
  361.     mouse_hide_cursor();
  362.  
  363. return(prognum);
  364. }
  365.  
  366.  
  367. /****************************************************************************
  368. ** Builds the appropriate strings from the inventory array and displays       **
  369. ** them on top of the current walls.                       **
  370. **                                       **
  371. ****************************************************************************/
  372. void ShowInventory(void)
  373. {
  374.     int        i,row;
  375.     char    mBuf[30];
  376.  
  377. smWriteHUD(VP_TEXTX,VP_TEXTY,2,"Inventory:");
  378. row = 10;
  379.  
  380. for (i = 0; i < OBJECT_COUNT; i++)
  381.     {
  382.     strcpy(mBuf,ObjectText[i]);
  383.     if (ObjectList[i] != 1)
  384.     strcat(mBuf,"No");
  385.     else
  386.     strcat(mBuf,"Yes");
  387.  
  388.     smWriteHUD(VP_TEXTX,VP_TEXTY+row,2,mBuf);
  389.     row += 10;
  390.     }
  391.  
  392. /* Debug line to show how much memory the system has left */
  393.  
  394. sprintf(mBuf,"Memory.........%dK",farcoreleft()/1024L);
  395. smWriteHUD(VP_TEXTX,VP_TEXTY+row,2,mBuf);
  396.  
  397. }
  398.  
  399.  
  400. /****************************************************************************
  401. ** Displays the contents of the specified text file onto the viewport       **
  402. ** window.                                   **
  403. **                                       **
  404. ****************************************************************************/
  405. void ShowTextFile(char *fName)
  406. {
  407.     int        x,y;
  408.     char    buf[80];
  409.     FILE    *fp;
  410.  
  411. fp = fopen(fName,"rt");
  412. if (fp == NULL)
  413.     return;
  414.  
  415. x = VP_TEXTX;
  416. y = VP_TEXTY;
  417.  
  418. mouse_hide_cursor();
  419. ShowColor(7);
  420.  
  421. while (1)
  422.     {
  423.     if (feof(fp))
  424.     break;
  425.  
  426.     *buf = '\0';
  427.     fgets(buf,78,fp);
  428.  
  429.     y = smWriteString(x,y,buf);
  430.  
  431.     }
  432.  
  433. mouse_show_cursor();
  434.  
  435. fclose(fp);
  436. }
  437.  
  438.  
  439.  
  440. /****************************************************************************
  441. ** Changes the shape of the mouse cursor when in UW2 mode.           **
  442. **                                       **
  443. ****************************************************************************/
  444. void SetMouseCursor(int index)
  445. {
  446.  
  447. mouse_set_graphics_cursor(mCursors[index].hy,
  448.               mCursors[index].hx,
  449.               (UCHAR far *)mCursors[index].Cursor);
  450.  
  451. }
  452.  
  453.  
  454. /****************************************************************************
  455. ** Keyboard interrupt 9                               **
  456. ****************************************************************************/
  457. void interrupt myInt(void)
  458. {
  459.   register char x;
  460.  
  461. scanCode = inp(0x60); // read keyboard data port
  462. x = inp(0x61);
  463. outp(0x61, (x | 0x80));
  464. outp(0x61, x);
  465. outp(0x20, 0x20);
  466.  
  467. Keys[scanCode & 127] = 1;
  468. if (scanCode & 128)
  469.     Keys[scanCode & 127] = 0;
  470.  
  471. }
  472.  
  473. /****************************************************************************
  474. ** Our timer countdown routine. For game time we are counting down faster  **
  475. ** than real time (adds to the suspense?).                   **
  476. **                                       **
  477. ****************************************************************************/
  478. void interrupt MyTimer(void)
  479. {
  480.  
  481. tmCounter++;
  482.  
  483. if (tmSeconds == 0 &&
  484.     tmMinutes == 0 &&
  485.     tmHours == 0)
  486.     return;
  487.  
  488. tmDelay--;
  489.  
  490. if (!tmDelay)
  491.     {
  492.     tmDelay = TIME_DELAY;
  493.     tmSeconds--;
  494.     if (tmSeconds < 0)
  495.     {
  496.     tmSeconds = 59;
  497.     tmMinutes--;
  498.     if (tmMinutes < 0)
  499.         {
  500.         if (tmHours)
  501.         {
  502.         tmHours--;
  503.         tmMinutes = 59;
  504.         }
  505.         else
  506.         tmMinutes = tmSeconds = 0;
  507.         }
  508.     }
  509.     }
  510. }
  511.  
  512. /****************************************************************************
  513. ** Routine currently not used. This allows the Wolf style mouse actions       **
  514. ** It is called once during InitializeMouse()                   **
  515. ****************************************************************************/
  516. void CheckMouse(MOUSE *m)
  517. {
  518.     int        dx,dy;
  519.     int        x,y,buttons;
  520.  
  521.  
  522. if (HaveMouse)
  523.     {
  524.     mouse_read_cursor(&buttons,&y,&x);
  525.     dx = x - 160;
  526.     dy = y - 120;
  527.     m->mButtons = buttons;
  528.     mouse_set_cursor(120,160);
  529.  
  530.     if (abs(dy) > 10 && abs(dx) < 32)
  531.     dx >>= 2;
  532.  
  533.     m->mdx = dx;
  534.     m->mdy = dy;
  535.  
  536.     }
  537.  
  538. }
  539.  
  540. /****************************************************************************
  541. ** Determines if the mouse is present.                       **
  542. **                                       **
  543. ****************************************************************************/
  544. int InitializeMouse(void)
  545. {
  546.  
  547. memset(&mouse,0,sizeof(MOUSE));
  548. HaveMouse = 0;
  549. if (mouse_installed() == -1)
  550.     {
  551.     HaveMouse = 1;
  552.     CheckMouse(&mouse);
  553.     }
  554.  
  555. return(HaveMouse);
  556. }
  557.  
  558. /****************************************************************************
  559. ** This routine simply runs through the video and replaces any old colors  **
  560. ** with a new color. Good for special effects when text is being displayed **
  561. **                                       **
  562. ****************************************************************************/
  563. void ReplaceColor(UCHAR OldColor,UCHAR NewColor)
  564. {
  565.     int        rows,cols;
  566.     UCHAR   far *Video;
  567.  
  568. Video = MK_FP(0xA000,VIDEO_OFFSET);
  569.  
  570. for (rows = 0; rows < VIDEO_ROWS; rows++)
  571.     {
  572.     for (cols = 0; cols < VIDEO_COLS; cols++)
  573.     {
  574.     if (Video[cols] == OldColor)
  575.         Video[cols] = NewColor;
  576.  
  577.     }
  578.     Video += 320;
  579.     }
  580.  
  581. }
  582.  
  583. /****************************************************************************
  584. ** Essentially a clear screen buffer to the specified color. Allows setting**
  585. ** the background color that appears in the viewport window when text is   **
  586. ** being displayed.                               **
  587. ****************************************************************************/
  588. void ShowColor(UCHAR color)
  589. {
  590.  
  591. memset(ae->ScreenBuffer,color,64000);
  592. AckDrawOverlay(ae->ScreenBuffer,ae->OverlayBuffer);
  593. AckDisplayScreen(ae);
  594.  
  595. }
  596.  
  597.  
  598. /* This is actually in the ACK engine lib */
  599. extern UINT  far *Grid;
  600.  
  601. /****************************************************************************
  602. ** Displays an overhead map of the entire station. This routine relies on  **
  603. ** external variables in the ACK engine and is kind of a cheat from the       **
  604. ** proper way of keeping the application isolated from the engine.       **
  605. **                                       **
  606. ****************************************************************************/
  607. void ShowOverhead(void)
  608. {
  609.     int        row,col,mPos,offset;
  610.     int        MidRow,MidCol,MidOffset;
  611.     int        mx,my,mbuttons,gCode;
  612.     UCHAR   Color;
  613.     UCHAR   far *Video;
  614.  
  615.  
  616. mouse_hide_cursor();
  617. ShowColor(7);
  618.  
  619. mx = VP_STARTX + (((VP_ENDX - VP_STARTX) - 128) / 2);
  620.  
  621. my = VP_STARTY + (((VP_ENDY - VP_STARTY) - 64) / 2);
  622.  
  623. Video = MK_FP(0xA000,(my * 320) + mx);
  624.  
  625.  
  626. MidRow = ae->yPlayer >> 6;
  627. MidCol = ae->xPlayer >> 6;
  628.  
  629. for (row = 0; row < GRID_HEIGHT; row++)
  630.     {
  631.     offset = 0;
  632.     for (col = 0; col < GRID_WIDTH; col++)
  633.     {
  634.     mPos = (row << 6) + col;
  635.  
  636.     gCode = Grid[mPos];
  637.  
  638.     switch (gCode & 0xFF)
  639.         {
  640.         case 0:
  641.         Color = 0;
  642.         break;
  643.  
  644.         case DOOR_XCODE:
  645.         case DOOR_YCODE:
  646.         Color = 9;
  647.         break;
  648.  
  649.         default:
  650.         Color = 15;
  651.         if (gCode & 0x80)
  652.             Color = 12;
  653.         break;
  654.         }
  655.  
  656.     if (gCode & DOOR_TYPE_SECRET)
  657.         Color = 11;
  658.  
  659.  
  660.     if (row == MidRow && col == MidCol)
  661.         {
  662.         Color = 12;
  663.         MidOffset = FP_OFF(Video) + offset;
  664.         }
  665.  
  666.     Video[offset] = Color;
  667.     Video[offset+1] = Color;
  668.  
  669.     offset += 2;
  670.     }
  671.  
  672.     Video += 320;
  673.     }
  674.  
  675. Video = MK_FP(0xA000,MidOffset);
  676.  
  677. mouse_show_cursor();
  678. mouse_released();
  679.  
  680. mPos = 0;
  681. row = 500;
  682.  
  683. while (1)
  684.     {
  685.     mouse_read_cursor(&mbuttons,&my,&mx);
  686.  
  687.     if (mbuttons & 1)
  688.     break;
  689.  
  690.     if (Keys[ENTER_KEY])
  691.     break;
  692.  
  693.     row--;
  694.     if (!row)
  695.     {
  696.     Video[0] = mPos;
  697.     Video[1] = mPos;
  698.     mPos ^= 12;
  699.     if (mPos)
  700.         row = 100;
  701.     else
  702.         row = 500;
  703.     }
  704.     }
  705.  
  706. mouse_released();
  707.  
  708. }
  709.  
  710. /****************************************************************************
  711. ** Pauses here until mouse button is released                   **
  712. ****************************************************************************/
  713. void mouse_released(void)
  714. {
  715.     int        mbutton,mx,my;
  716.  
  717. mouse_read_cursor(&mbutton,&my,&mx);
  718. while (mbutton)
  719.     mouse_read_cursor(&mbutton,&my,&mx);
  720.  
  721. }
  722.  
  723.  
  724. /****************************************************************************
  725. ** Checks the location of the mouse to see if the mouse cursor needs to       **
  726. ** change shape (used in UW2 mode).                       **
  727. **                                       **
  728. ****************************************************************************/
  729. void CheckMouseCursor(int x,int y)
  730. {
  731.     int        index;
  732.  
  733. index = 0;
  734.  
  735. if (y >= VP_STARTY && y <= VP_ENDY && x >= VP_STARTX && x <= VP_ENDX)
  736.     {
  737.  
  738.     if (x < VP_LARROWX)
  739.     index = MOUSE_LTARROW;
  740.  
  741.     if (x > VP_RARROWX)
  742.     index = MOUSE_RTARROW;
  743.  
  744.     if (x >= VP_LARROWX && x <= VP_RARROWX)
  745.     {
  746.     if (y < VP_UDARROWY)
  747.         index = MOUSE_UPARROW;
  748.     else
  749.         index = MOUSE_DNARROW;
  750.     }
  751.  
  752.     }
  753.  
  754.  
  755. if (index != LastMouseIndex)
  756.     {
  757.     SetMouseCursor(index);
  758.     LastMouseIndex = index;
  759.     }
  760.  
  761. }
  762.  
  763. /****************************************************************************
  764. ** Update all the walls as needed.                       **
  765. ****************************************************************************/
  766. void AnimateWalls(void)
  767. {
  768.     int        i;
  769.  
  770. ae->bMaps[WallType[0]] = wMaps[WallIndex];
  771. WallIndex++;
  772. if (WallIndex > 2)
  773.     WallIndex = 0;
  774.  
  775. WallDelay--;
  776. if (WallDelay)
  777.     return;
  778.  
  779. WallDelay = WALL_DELAY;
  780.  
  781. ae->bMaps[WallType1[0]] = wMaps1[WallIndex1];
  782.  
  783. WallIndex1++;
  784. if (WallIndex1 > 3)
  785.     WallIndex1 = 0;
  786.  
  787. ae->bMaps[WallType2[0]] = wMaps2[WallIndex2];
  788. WallIndex2++;
  789. if (WallIndex2 > 1)
  790.     WallIndex2 = 0;
  791.  
  792. ae->bMaps[WallType3[0]] = wMaps3[WallIndex3];
  793. WallIndex3++;
  794. if (WallIndex3 > 1)
  795.     WallIndex3 = 0;
  796.  
  797. ae->bMaps[WallType4[0]] = wMaps4[WallIndex4];
  798. WallIndex4++;
  799. if (WallIndex4 > 1)
  800.     WallIndex4 = 0;
  801.  
  802. }
  803.  
  804. /****************************************************************************
  805. ** Setup pointers to animated wall bitmaps                   **
  806. ****************************************************************************/
  807. void SetupAnimatedWalls(void)
  808. {
  809.     int        i;
  810.  
  811. for (i = 0; i < 3; i++)
  812.     wMaps[i] = ae->bMaps[WallType[i]];
  813.  
  814. for (i = 0; i < 4; i++)
  815.     wMaps1[i] = ae->bMaps[WallType1[i]];
  816.  
  817. for (i = 0; i < 2; i++)
  818.     wMaps2[i] = ae->bMaps[WallType2[i]];
  819.  
  820. for (i = 0; i < 2; i++)
  821.     wMaps3[i] = ae->bMaps[WallType3[i]];
  822.  
  823. for (i = 0; i < 2; i++)
  824.     wMaps4[i] = ae->bMaps[WallType4[i]];
  825.  
  826. for (i = 0; i < 4; i++)
  827.     hMaps[i] = ae->bMaps[HoloWalls[i]];
  828.  
  829. WallIndex = 1;
  830. WallIndex1 = 1;
  831. WallIndex2 = 1;
  832. WallIndex3 = 1;
  833. WallIndex4 = 1;
  834. HoloIndex = 0;
  835.  
  836. }
  837.  
  838.  
  839. /****************************************************************************
  840. ** Display the time remaining to the player.                   **
  841. ****************************************************************************/
  842. void ShowTime(void)
  843. {
  844.     char    buf[48];
  845.  
  846. sprintf(buf,"Time remaining: %02d:%02d:%02d",tmHours,tmMinutes,tmSeconds);
  847. smWriteString(VP_TIMEX,VP_TIMEY,buf);
  848.  
  849. }
  850.  
  851. /****************************************************************************
  852. ** Clears the statusline section at the bottom of the screen to the color  **
  853. ** specified.                                   **
  854. **                                       **
  855. ****************************************************************************/
  856. void ClearStatusLine(UCHAR color)
  857. {
  858.     int        rows,cols;
  859.     UCHAR   far *Video;
  860.  
  861. rows = (VP_STATUSY * 320) + VP_STATUSX;
  862. Video = MK_FP(0xA000,rows);
  863.  
  864. cols = (VP_STATUSX1 - VP_STATUSX) + 1;
  865.  
  866. for (rows = VP_STATUSY; rows < VP_STATUSY1; rows++)
  867.     {
  868.     memset(Video,color,cols);
  869.     Video += 320;
  870.     }
  871.  
  872. }
  873.  
  874. /****************************************************************************
  875. ** Displays the energy bar underneath the viewport.               **
  876. **                                       **
  877. ****************************************************************************/
  878. void ShowLightbar(void)
  879. {
  880.     int        row,col1,col2;
  881.     UCHAR   far *Video;
  882.  
  883. Video = MK_FP(0xA000,VP_LIGHTBAR_OFFSET);
  884.  
  885. if (BoltEnergy < 0)
  886.     BoltEnergy = 0;
  887.  
  888. col1 = BoltEnergy * 2;
  889.  
  890. if (col1 >= VP_LIGHTBAR_COLS)
  891.     col1 = VP_LIGHTBAR_COLS - 1;
  892.  
  893. col2 = (VP_LIGHTBAR_COLS - col1) - 1;
  894.  
  895. if (col2)
  896.     col2++;
  897. else
  898.     col1++;
  899.  
  900. for (row = 0; row < VP_LIGHTBAR_ROWS; row++)
  901.     {
  902.     if (col1)
  903.     memset(Video,2,col1);
  904.     if (col2)
  905.     memset(&Video[col1],4,col2);
  906.     Video += 320;
  907.     }
  908.  
  909. }
  910.  
  911. /****************************************************************************
  912. ** Makes a call into the library to play the specified sound effect.       **
  913. **                                       **
  914. ****************************************************************************/
  915. void AppPlaySound(int VocIndex)
  916. {
  917. #if USE_SOUND
  918.     AckPlaySound(VocIndex);
  919. #else
  920.     VocIndex--;        /* Keep compiler happy */
  921. #endif
  922. }
  923.  
  924. /****************************************************************************
  925. ** Check for objects hit and take the appropriate action. This routine is  **
  926. ** called when the player moves and strikes something.               **
  927. ****************************************************************************/
  928. void CheckOurObjects(void)
  929. {
  930.     int        i;
  931.  
  932. i = AckGetObjectHit();    /* Get index to object */
  933.  
  934. switch(i)
  935.     {
  936.     case 1:
  937.     case 2:
  938.     case 29:
  939.     AppPlaySound(SOUND_HITBADOBJECT);
  940.     if (BoltEnergy)
  941.         BoltEnergy--;
  942.     ShowLightbar();
  943.     break;
  944.  
  945.     case 10:
  946.     case 39:
  947.     AppPlaySound(SOUND_HITOBJECT);
  948.     BoltEnergy += 30;
  949.     if (BoltEnergy > 77) BoltEnergy = 77;
  950.  
  951.     ShowLightbar();
  952.     AckDeleteObject(ae,i);
  953.     break;
  954.  
  955.     case 8:
  956.     case 9:
  957.     case 25:
  958.     case 27:
  959.     AppPlaySound(SOUND_HITOBJECT);
  960.     if (i == 25 && ObjectList[OBJ_COMPUTER] == 2)
  961.         break;
  962.  
  963.     if (i == 27 && ObjectList[OBJ_FUELCELLS] == 2)
  964.         break;
  965.  
  966.     if (TotalInventory < MAX_INVENTORY)
  967.         {
  968.         AckDeleteObject(ae,i);
  969.         Inventory[TotalInventory++] = i;
  970.         if (i == 25)
  971.         ObjectList[OBJ_COMPUTER] = 1;
  972.  
  973.         if (i == 27)
  974.         ObjectList[OBJ_FUELCELLS] = 1;
  975.         }
  976.     break;
  977.  
  978.     case 26:
  979.     AppPlaySound(SOUND_HITOBJECT);
  980.     if (ObjectList[OBJ_CIRCUITBOARD] == 2)
  981.         break;
  982.  
  983.     if (TotalInventory < MAX_INVENTORY)
  984.         {
  985.         AckDeleteObject(ae,26);
  986.         UnlockDoors();
  987.         Inventory[TotalInventory++]= 26;
  988.         ObjectList[OBJ_CIRCUITBOARD] = 1;
  989.         }
  990.     break;
  991.  
  992.     default:
  993.     if (i < 50)
  994.         AppPlaySound(SOUND_HITOBJECT);
  995.     break;
  996.  
  997.     }
  998.  
  999. }
  1000.  
  1001. /****************************************************************************
  1002. ** This routine will unlock ALL doors in the map               **
  1003. ****************************************************************************/
  1004. void UnlockDoors(void)
  1005. {
  1006.     int        i;
  1007.  
  1008. for (i = 0; i < GRID_MAX; i++)
  1009.     {
  1010.     if (ae->xGrid[i] & DOOR_LOCKED)
  1011.     ae->xGrid[i] &= ~DOOR_LOCKED;
  1012.  
  1013.     if (ae->yGrid[i] & DOOR_LOCKED)
  1014.     ae->yGrid[i] &= ~DOOR_LOCKED;
  1015.     }
  1016.  
  1017.  
  1018. }
  1019.  
  1020.  
  1021.  
  1022. /****************************************************************************
  1023. ** Check for doors opening or closing and play the appropriate sound.       **
  1024. **                                       **
  1025. ****************************************************************************/
  1026. void PlayDoorSounds(void)
  1027. {
  1028.     int        i,DoorColumn;
  1029.  
  1030. for (i = 0; i < MAX_DOORS; i++)
  1031.     {
  1032.     if (ae->Door[i].ColOffset)
  1033.     {
  1034.     DoorColumn = 64;
  1035.     if (ae->Door[i].mCode & DOOR_TYPE_SPLIT)
  1036.         DoorColumn = 32;
  1037.  
  1038.     if (ae->Door[i].ColOffset < DoorColumn)
  1039.         {
  1040.         if (ae->Door[i].Flags & DOOR_OPENING)
  1041.         {
  1042.         AppPlaySound(SOUND_DOOROPENING);
  1043.         ae->Door[i].Flags &= ~DOOR_OPENING;
  1044.         }
  1045.  
  1046.         if (ae->Door[i].Flags & DOOR_CLOSING)
  1047.         {
  1048.         AppPlaySound(SOUND_DOORCLOSING);
  1049.         ae->Door[i].Flags &= ~DOOR_CLOSING;
  1050.         }
  1051.         }
  1052.     }
  1053.     }
  1054.  
  1055. }
  1056.  
  1057.  
  1058. /****************************************************************************
  1059. ** Move the energy bolt and check for collision with walls or objects.       **
  1060. ** If a wall is hit then display damage, if a porthole is hit then the       **
  1061. ** station decompresses and the player loses.                   **
  1062. **                                       **
  1063. ****************************************************************************/
  1064. void UpdateBomb(void)
  1065. {
  1066.     int        oNum,j,wCode,bCode,NewCode;
  1067.     int        hFlag;
  1068.  
  1069. oNum = MAX_OBJECTS-1;
  1070. wCode = 0;
  1071. hFlag = 0;
  1072.  
  1073. j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
  1074.  
  1075. if (j != POV_NOTHING && j != POV_PLAYER)
  1076.     {
  1077.     ae->ObjList[oNum].Active = 0;
  1078.     Shooting = 0;
  1079.     oNum = AckGetWallHit();
  1080.  
  1081.     if (j == POV_XWALL)
  1082.     {
  1083.     AppPlaySound(SOUND_EXPLODE);
  1084.     wCode = ae->xGrid[oNum] & 0xFF;
  1085.  
  1086.     bCode = wCode & 0x3F;
  1087.  
  1088.     if (bCode == 25)
  1089.         ae->ObjList[MAX_OBJECTS-2].Active = 0;
  1090.  
  1091.     if (bCode >= WallType1[0] && bCode <= WallType1[3])
  1092.         Decompress = 1;
  1093.  
  1094.     if (bCode > 21 && bCode < 25)
  1095.         Decompress = 1;
  1096.  
  1097.     if (bCode == HoloWalls[0] || bCode == HoloWalls[1])
  1098.         hFlag = 1;
  1099.  
  1100.     if (bCode < DOOR_XCODE && !hFlag)
  1101.         {
  1102.         bCode = wCode | 0x80;
  1103.         NewCode = 57;
  1104.  
  1105.         if (wCode == bCode)
  1106.         {
  1107.         bCode |= 0xC0;
  1108.         NewCode = 56;
  1109.         }
  1110.  
  1111.         if (ae->bMaps[bCode] == NULL)
  1112.         {
  1113.         ae->bMaps[bCode] = AckCopyNewBitmap(ae->bMaps[wCode]);
  1114.         if (ae->bMaps[bCode] != NULL)
  1115.             AckOverlayBitmap(ae->bMaps[bCode],ae->bMaps[NewCode]);
  1116.         }
  1117.  
  1118.         if (ae->bMaps[bCode] != NULL)
  1119.         ae->xGrid[oNum] = bCode;
  1120.  
  1121.         }
  1122.  
  1123.     }
  1124.  
  1125.     if (j == POV_YWALL)
  1126.     {
  1127.     AppPlaySound(SOUND_EXPLODE);
  1128.     wCode = ae->yGrid[oNum] & 0xFF;
  1129.     bCode = wCode & 0x3F;
  1130.  
  1131.     if (bCode == 25)
  1132.         ae->ObjList[MAX_OBJECTS-2].Active = 0;
  1133.  
  1134.     if (bCode >= WallType1[0] && bCode <= WallType1[3])
  1135.         Decompress = 1;
  1136.  
  1137.     if (bCode == HoloWalls[0] || bCode == HoloWalls[1])
  1138.         hFlag = 1;
  1139.  
  1140.     if (bCode < DOOR_XCODE && !hFlag)
  1141.         {
  1142.         bCode = wCode | 0x80;
  1143.         NewCode = 57;
  1144.  
  1145.         if (wCode == bCode)
  1146.         {
  1147.         bCode |= 0xC0;
  1148.         NewCode = 56;
  1149.         }
  1150.         if (ae->bMaps[bCode] == NULL)
  1151.         {
  1152.         ae->bMaps[bCode] = AckCopyNewBitmap(ae->bMaps[wCode]);
  1153.         if (ae->bMaps[bCode] != NULL)
  1154.             AckOverlayBitmap(ae->bMaps[bCode],ae->bMaps[NewCode]);
  1155.         }
  1156.  
  1157.  
  1158.         if (ae->bMaps[bCode] != NULL)
  1159.         ae->yGrid[oNum] = bCode;
  1160.  
  1161.         }
  1162.  
  1163.     }
  1164.  
  1165.     if (j == POV_OBJECT)
  1166.     {
  1167.     oNum = AckGetObjectHit();
  1168.     if (oNum >= 50 && oNum < 70)
  1169.         {
  1170.         if (ae->ObjList[oNum].Flags & OF_ANIMATE)
  1171.         {
  1172.         AppPlaySound(SOUND_USER2);
  1173.         AckDeleteObject(ae,oNum+20);
  1174.         ae->ObjList[oNum].Flags &= ~OF_ANIMATE;
  1175.         ae->ObjList[oNum].Flags |= OF_PASSABLE;
  1176.         ae->ObjList[oNum].CurNum = 0;
  1177.         ae->ObjList[oNum].MaxNum = 0;
  1178.         ae->ObjList[oNum].bmNum[0] = 51;
  1179.         ae->ObjList[oNum].Speed = 1;
  1180.         }
  1181.         else
  1182.         Shooting = 1;
  1183.         }
  1184.     }
  1185.     }
  1186. else
  1187.     {
  1188.     ae->ObjList[oNum].CurNum++;
  1189.     if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
  1190.     ae->ObjList[oNum].CurNum = 0;
  1191.     }
  1192.  
  1193. if (wCode)
  1194.     {
  1195.     wCode &= 0x3F;
  1196.     if (wCode == 36)
  1197.     {
  1198.     smWriteString(180,VP_TIMEY,"   You are so cruel!        ");
  1199.     }
  1200.  
  1201.     if (hFlag && HoloIndex < 2)
  1202.     {
  1203.     HoloIndex = 2;
  1204.     smWriteString(180,VP_TIMEY,"Holodeck program terminated.");
  1205.     ae->bMaps[HoloWalls[0]] = hMaps[HoloIndex];
  1206.     ae->ObjList[3].Active = 0;
  1207.     ae->ObjList[4].Active = 0;
  1208.     ae->ObjList[9].Active = 0;
  1209.     ae->ObjList[11].Active = 0;
  1210.     }
  1211.     }
  1212.  
  1213. }
  1214.  
  1215. /****************************************************************************
  1216. ** This is one example of moving a very specific object around in the map. **
  1217. ** In this case the bolt of energy in the plasma lab is shot out of one       **
  1218. ** wall, moves across the room until striking the other wall and then       **
  1219. ** starts over.                                   **
  1220. ****************************************************************************/
  1221. void UpdateWallBolt(void)
  1222. {
  1223.     int        oNum,j,wCode;
  1224.  
  1225. oNum = MAX_OBJECTS-2;
  1226.  
  1227. if (!ae->ObjList[oNum].Active)
  1228.     return;
  1229.  
  1230. j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
  1231.  
  1232. if (j != POV_NOTHING)
  1233.     {
  1234.     if (j == POV_PLAYER)
  1235.     {
  1236.     AppPlaySound(SOUND_HITBADOBJECT);
  1237.     mouse_hide_cursor();
  1238.     ShowColor(4);
  1239.     if (BoltEnergy)
  1240.         {
  1241.         BoltEnergy--;
  1242.         ShowLightbar();
  1243.         }
  1244.     mouse_show_cursor();
  1245.     }
  1246.     ae->ObjList[oNum].x = 1184;
  1247.     ae->ObjList[oNum].y = 2976;
  1248.     }
  1249. else
  1250.     {
  1251.     ae->ObjList[oNum].CurNum++;
  1252.     if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
  1253.     ae->ObjList[oNum].CurNum = 0;
  1254.     }
  1255.  
  1256. }
  1257.  
  1258. /****************************************************************************
  1259. ** This routine updates all the spacemen in the station, first by changing **
  1260. ** the bitmap that is displayed and second, by updating any plasma bolts   **
  1261. ** they may have fired. Note that all the work is done here and the ACK       **
  1262. ** engine is only called to actually move the objects. The result of the   **
  1263. ** movement is then checked to see if the player was hit or not.       **
  1264. **                                       **
  1265. ****************************************************************************/
  1266. void UpdateSpaceMen(void)
  1267. {
  1268.     int        i,j,x,y,px,py,oNum,angle,oHit;
  1269.     int        dx,dy,x1,y1;
  1270.  
  1271. x1 = px = ae->xPlayer;
  1272. y1 = py = ae->yPlayer;
  1273.  
  1274. for (i = 50; i < 70; i++)
  1275.     {
  1276.     if (!ae->ObjList[i].Active || !(ae->ObjList[i].Flags & OF_ANIMATE))
  1277.     {
  1278.     if (ae->ObjList[i].bmNum[0] > 48)
  1279.         {
  1280.         if (ae->ObjList[i].Speed-- <= 0)
  1281.         {
  1282.         ae->ObjList[i].bmNum[0]--;
  1283.         ae->ObjList[i].Speed = 1;
  1284.         }
  1285.         }
  1286.     continue;
  1287.     }
  1288.  
  1289.     oNum = i + 20;
  1290.  
  1291.     if (!ae->ObjList[oNum].Active)
  1292.     {
  1293.     if (SpaceMenDelay[i-50] > tmCounter)
  1294.         continue;
  1295.  
  1296.     x = ae->ObjList[i].x;
  1297.     y = ae->ObjList[i].y;
  1298.  
  1299.     px = x1;
  1300.     py = y1;
  1301.  
  1302.     dx = abs(px - x);
  1303.     dy = abs(py - y);
  1304.  
  1305.     if (dx > dy)
  1306.         py = y;
  1307.  
  1308.     if (dx < dy)
  1309.         px = x;
  1310.  
  1311.     if (py == y)
  1312.         {
  1313.         if (px < x) angle = INT_ANGLE_180;
  1314.         if (px > x) angle = 0;
  1315.         }
  1316.  
  1317.     if (px == x)
  1318.         {
  1319.         if (py < y) angle = INT_ANGLE_270;
  1320.         if (py > y) angle = INT_ANGLE_90;
  1321.         }
  1322.  
  1323.     ae->ObjList[oNum].Active = 1;
  1324.     ae->ObjList[oNum].x = x;
  1325.     ae->ObjList[oNum].y = y;
  1326.     ae->ObjList[oNum].Dir = angle;
  1327.     }
  1328.  
  1329.     j = AckMoveObjectPOV(ae,oNum,ae->ObjList[oNum].Dir,ae->ObjList[oNum].Speed);
  1330.  
  1331.     if (j != POV_NOTHING)
  1332.     {
  1333.     oHit = AckGetObjectHit();
  1334.     if (oHit == i)
  1335.         j = POV_NOTHING;
  1336.     }
  1337.  
  1338.     if (j != POV_NOTHING)
  1339.     {
  1340.     if (j == POV_PLAYER)
  1341.         {
  1342.         AppPlaySound(SOUND_HITBADOBJECT);
  1343.         mouse_hide_cursor();
  1344.         ShowColor(4);
  1345.         if (BoltEnergy)
  1346.         {
  1347.         BoltEnergy -= 3;
  1348.         if (BoltEnergy < 0)
  1349.             BoltEnergy = 0;
  1350.  
  1351.         ShowLightbar();
  1352.         }
  1353.         mouse_show_cursor();
  1354.         }
  1355.  
  1356.     ae->ObjList[oNum].Active = 0;
  1357.     SpaceMenDelay[i-50] = tmCounter + random(30);
  1358.     }
  1359.     else
  1360.     {
  1361.     ae->ObjList[oNum].CurNum++;
  1362.     if (ae->ObjList[oNum].CurNum >= ae->ObjList[oNum].MaxNum)
  1363.         ae->ObjList[oNum].CurNum = 0;
  1364.     }
  1365.  
  1366.     }
  1367.  
  1368.  
  1369. }
  1370.  
  1371.  
  1372. /****************************************************************************
  1373. ** Display the instruction text and wait for the ENTER key to be pressed.  **
  1374. ****************************************************************************/
  1375. void ShowInstructions(void)
  1376. {
  1377.     int        mx,my,mbuttons;
  1378.  
  1379. FontColor = 0;
  1380. TextBGcolor = 7;
  1381.  
  1382. mouse_hide_cursor();
  1383. ShowTextFile("instr.txt");
  1384. mouse_show_cursor();
  1385. mouse_released();
  1386.  
  1387. FontColor = 15;
  1388.  
  1389. while (!Keys[ENTER_KEY])
  1390.     {
  1391.     mouse_read_cursor(&mbuttons,&my,&mx);
  1392.     if (mbuttons)
  1393.     break;
  1394.     }
  1395.  
  1396. }
  1397.  
  1398. extern UCHAR far colordat[];
  1399.  
  1400. /****************************************************************************
  1401. ** Displays the rotating compass under the viewport depending on what       **
  1402. ** direction the player is facing.                       **
  1403. ****************************************************************************/
  1404. void ShowCompass(void)
  1405. {
  1406.     int        x,wt;
  1407.     UCHAR   far *Src,*sBuf;
  1408.  
  1409. sBuf = ae->ScreenBuffer + 45896;
  1410.  
  1411. wt = (*(int *)CompassBmp);
  1412. x = ae->PlayerAngle / 8;
  1413.  
  1414. x -= 17;
  1415. if (x < 0)
  1416.     x += 240;
  1417.  
  1418. Src = CompassBmp + x + 4;
  1419.  
  1420. for (x = 0; x < 7; x++)
  1421.     {
  1422.     memmove(sBuf,Src,49);
  1423.     sBuf += 320;
  1424.     Src += wt;
  1425.     }
  1426.  
  1427. }
  1428.  
  1429. /****************************************************************************
  1430. ** Quicky routine to display the specified bitmap on the video. Used to       **
  1431. ** show the objects being carried so they can be dropped.           **
  1432. **                                       **
  1433. ****************************************************************************/
  1434. void ShowBitmap(int x,int y,UCHAR far *Bmp)
  1435. {
  1436.     int        row,col;
  1437.     UCHAR   far *Video;
  1438.     UCHAR   far *vPtr;
  1439.  
  1440. Video = MK_FP(0xA000,(y * 320) + x);
  1441.  
  1442. for (col = 0; col < 64; col++)
  1443.     {
  1444.     vPtr = Video;
  1445.     for (row = 0; row < 64; row++)
  1446.     {
  1447.     *vPtr = *Bmp++;
  1448.     vPtr += 320;
  1449.     }
  1450.     Video++;
  1451.     }
  1452.  
  1453.  
  1454. }
  1455.  
  1456. /****************************************************************************
  1457. ** Clears the screen and shows the objects currently carried by the player.**
  1458. ** Note that the ACK engine must be called to get a pointer to the bitmap  **
  1459. ** since it could be in XMS memory.                       **
  1460. ****************************************************************************/
  1461. void ShowInventoryObjects(void)
  1462. {
  1463.     int        i,x,y;
  1464.     UCHAR   far *Video;
  1465.     UCHAR   far *Bmp;
  1466.  
  1467. Video = MK_FP(0xA000,0);
  1468. mouse_hide_cursor();
  1469. memmove(ae->ScreenBuffer,Video,64000);
  1470. memset(Video,0,64000);
  1471. x = y = 0;
  1472.  
  1473. for (i = 0; i < TotalInventory; i++)
  1474.     {
  1475.     Bmp = AckGetBitmapPtr(ae->ObjList[Inventory[i]].bmNum[0],ae->oMaps);
  1476.     ShowBitmap(x,y,Bmp);
  1477.  
  1478.     x += 64;
  1479.     if (x > 256)
  1480.     {
  1481.     y += 64;
  1482.     x = 0;
  1483.     }
  1484.     }
  1485.  
  1486. Video = MK_FP(0xA000,57600U);
  1487. memset(Video,7,6400);
  1488. smWriteString(30,190,"Select object");
  1489. mouse_show_cursor();
  1490.  
  1491. }
  1492.  
  1493. /****************************************************************************
  1494. ** Shows the objects the player is carrying and then allows the player to  **
  1495. ** select an object to drop. When dropped the object has the current player**
  1496. ** location. A check is then made to see if all the required objects have  **
  1497. ** been dropped in the proper location to win the game.               **
  1498. ****************************************************************************/
  1499. void DropObject(void)
  1500. {
  1501.     int        done,oNum,iPos,mx,my,mbutton;
  1502.     int        px,py;
  1503.     UCHAR   far *Video;
  1504.  
  1505. if (!TotalInventory)
  1506.     return;
  1507.  
  1508. ShowInventoryObjects();
  1509.  
  1510. if (MouseMode)
  1511.     mouse_show_cursor();
  1512.  
  1513. px = ae->xPlayer >> 6;
  1514. py = ae->yPlayer >> 6;
  1515.  
  1516. done = 0;
  1517. while (!done)
  1518.     {
  1519.     mouse_read_cursor(&mbutton,&my,&mx);
  1520.  
  1521.     if (mbutton & 2 || Keys[ENTER_KEY])
  1522.     break;
  1523.  
  1524.     if (mbutton & 1)
  1525.     {
  1526.     my >>= 6;
  1527.     mx >>= 6;
  1528.     iPos = (my * 4) + mx;
  1529.     if (iPos < TotalInventory)
  1530.         {
  1531.         oNum = Inventory[iPos];
  1532.         ae->ObjList[oNum].Active = 1;
  1533.         ae->ObjList[oNum].x = ae->xPlayer;
  1534.         ae->ObjList[oNum].y = ae->yPlayer;
  1535.  
  1536.         mx = MAX_INVENTORY - iPos;
  1537.         memmove(&Inventory[iPos],&Inventory[iPos+1],mx);
  1538.         TotalInventory--;
  1539.  
  1540.         switch (oNum)
  1541.         {
  1542.         case 25:
  1543.             ObjectList[OBJ_COMPUTER] = 0;
  1544.             if (px > 40 && px < 46 && py > 48 && py < 53)
  1545.             ObjectList[OBJ_COMPUTER] = 2;
  1546.  
  1547.             break;
  1548.  
  1549.         case 26:
  1550.             ObjectList[OBJ_CIRCUITBOARD] = 0;
  1551.             if (px > 40 && px < 46 && py > 48 && py < 53)
  1552.             ObjectList[OBJ_CIRCUITBOARD] = 2;
  1553.             break;
  1554.  
  1555.         case 27:
  1556.             ObjectList[OBJ_FUELCELLS] = 0;
  1557.             if (px > 40 && px < 46 && py > 48 && py < 53)
  1558.             ObjectList[OBJ_FUELCELLS] = 2;
  1559.             break;
  1560.  
  1561.         default:
  1562.             break;
  1563.         }
  1564.         break;
  1565.         }
  1566.  
  1567.     }
  1568.  
  1569.  
  1570.     }
  1571.  
  1572. mouse_released();
  1573. Video = MK_FP(0xA000,0);
  1574. mouse_hide_cursor();
  1575. memmove(Video,ae->ScreenBuffer,64000);
  1576.  
  1577. if (!MouseMode)
  1578.     mouse_show_cursor();
  1579.  
  1580. for (mx = 0; mx < 3; mx++)
  1581.     {
  1582.     if (ObjectList[mx] != 2)
  1583.     return;
  1584.     }
  1585.  
  1586. YouWON = 1;
  1587.  
  1588. }
  1589.  
  1590. /****************************************************************************
  1591. ** This routine copies a DP2 brush file on top of the screen for later       **
  1592. ** display. Used in the title sequence to move the words over the station. **
  1593. **                                       **
  1594. ****************************************************************************/
  1595. void OverlayBrush(int x,int y,UCHAR far *Screen,UCHAR far *Brush)
  1596. {
  1597.     int        wt,ht,col;
  1598.     UINT    offset;
  1599.     UCHAR   ch;
  1600.  
  1601. wt = (*(int *)Brush);
  1602. Brush += 2;
  1603. ht = (*(int *)Brush);
  1604. Brush += 2;
  1605.  
  1606. if (y >= 0)
  1607.     offset = (y * 320) + x;
  1608. else
  1609.     offset = x;
  1610.  
  1611. Screen += offset;
  1612.  
  1613. for (;ht > 0; ht--)
  1614.     {
  1615.     if (y >= 0 && y < 199)
  1616.     {
  1617.     for (col = 0; col < wt; col++)
  1618.         {
  1619.         ch = *Brush++;
  1620.         if (ch)
  1621.         Screen[col] = ch;
  1622.         }
  1623.     Screen += 320;
  1624.     }
  1625.     else
  1626.     Brush += wt;
  1627.  
  1628.     if (++y > 199)
  1629.     break;
  1630.     }
  1631.  
  1632.  
  1633. }
  1634.  
  1635. /****************************************************************************
  1636. ** Displays the space station title.                       **
  1637. **                                       **
  1638. ****************************************************************************/
  1639. void ShowTitle(void)
  1640. {
  1641.     int        sx,sy,ex,ey,ax,ay,len;
  1642.     int        kFlag;
  1643.     UINT    offset;
  1644.     UCHAR   far *Video;
  1645.     UCHAR   far *Screen;
  1646.     UCHAR   far *tBuf;
  1647.     UCHAR   far *sBuf;
  1648.     UCHAR   far *eBuf;
  1649.     UCHAR   far *aBuf;
  1650.  
  1651. kFlag = 0;
  1652. Video = MK_FP(0xA000,0);
  1653.  
  1654. Screen = malloc(64000);
  1655. if (Screen == NULL)
  1656.     return;
  1657.  
  1658. tBuf = AckReadiff("bitmaps\\stat01.lbm");
  1659. if (tBuf != NULL)
  1660.     {
  1661.     memmove(tBuf,&tBuf[4],64000);
  1662.     memmove(Video,tBuf,64000);
  1663.     AckFadeIn(0,255,colordat);
  1664.     }
  1665.  
  1666. sBuf = AckReadiff("bitmaps\\station.bbm");
  1667. eBuf = AckReadiff("bitmaps\\escape.bbm");
  1668. aBuf = AckReadiff("bitmaps\\ack3d.bbm");
  1669.  
  1670. offset = 76 * 320;
  1671. len = 64000 - offset;
  1672.  
  1673. if (sBuf != NULL &&
  1674.     eBuf != NULL &&
  1675.     aBuf != NULL)
  1676.     {
  1677.     sx = 3;
  1678.     sy = -80;
  1679.     ex = 17;
  1680.     ey = 210;
  1681.     ax = 60;
  1682.     ay = 210;
  1683.  
  1684.     while (sy < 10)
  1685.     {
  1686.     memmove(Screen,tBuf,64000);
  1687.     OverlayBrush(sx,sy,Screen,sBuf);
  1688.     memmove(Video,Screen,len);
  1689.     sy++;
  1690.     if (kbhit())
  1691.         {
  1692.         kFlag = 1;
  1693.         getch();
  1694.         sy = 10;
  1695.         ey = 76;
  1696.         ay = 130;
  1697.         }
  1698.  
  1699.     }
  1700.  
  1701.     OverlayBrush(sx,sy,tBuf,sBuf);
  1702.  
  1703.     while (ey > 76)
  1704.     {
  1705.     memmove(Screen,tBuf,64000);
  1706.     OverlayBrush(ex,ey,Screen,eBuf);
  1707.     memmove(&Video[offset],&Screen[offset],len);
  1708.     ey--;
  1709.     if (kbhit())
  1710.         {
  1711.         kFlag = 1;
  1712.         getch();
  1713.         ey = 76;
  1714.         ay = 130;
  1715.         }
  1716.     }
  1717.  
  1718.     OverlayBrush(ex,ey,tBuf,eBuf);
  1719.  
  1720.     while (ay > 130)
  1721.     {
  1722.     memmove(Screen,tBuf,64000);
  1723.     OverlayBrush(ax,ay,Screen,aBuf);
  1724.     memmove(&Video[offset],&Screen[offset],len);
  1725.     ay--;
  1726.     if (kbhit())
  1727.         {
  1728.         kFlag = 1;
  1729.         getch();
  1730.         ay = 130;
  1731.         }
  1732.     }
  1733.  
  1734.     }
  1735.  
  1736.  
  1737. if (Screen != NULL)
  1738.     free(Screen);
  1739.  
  1740. if (tBuf != NULL)
  1741.     free(tBuf);
  1742.  
  1743. if (sBuf != NULL)
  1744.     free(sBuf);
  1745.  
  1746. if (eBuf != NULL)
  1747.     free(eBuf);
  1748.  
  1749. if (aBuf != NULL)
  1750.     free(aBuf);
  1751.  
  1752. if (!kFlag)
  1753.     {
  1754.     tBuf = AckReadiff("bitmaps\\credits.lbm");
  1755.     if (tBuf != NULL)
  1756.     {
  1757.     AckFadeOut(0,255);
  1758.     memmove(Video,&tBuf[4],64000);
  1759.     memset(tBuf,0,768);
  1760.     AckSetPalette(tBuf);
  1761.     AckFadeIn(0,255,colordat);
  1762.     ex = 500;
  1763.  
  1764.     while (ex--)
  1765.         {
  1766.         if (kbhit())
  1767.         {
  1768.         getch();
  1769.         break;
  1770.         }
  1771.         delay(10);
  1772.  
  1773.         }
  1774.     free(tBuf);
  1775.     }
  1776.     }
  1777.  
  1778. }
  1779.  
  1780. /****************************************************************************
  1781. ** Checks the map location of the player for special things, in this case  **
  1782. ** to see if the player is about ready to enter the holodeck.           **
  1783. **                                       **
  1784. ****************************************************************************/
  1785. void CheckPlayerSquare(void)
  1786. {
  1787.     int        row,col,mPos,hProg,aFlag;
  1788.  
  1789. row = ae->yPlayer >> 6;
  1790. col = ae->xPlayer >> 6;
  1791. mPos = (row << 6) + col;
  1792. aFlag = 0;
  1793.  
  1794. if (!HoloSoundFlag &&
  1795.     col == 11 &&
  1796.     ae->PlayerAngle > INT_ANGLE_180 &&
  1797.     row == 33)
  1798.     {
  1799.     hProg = PickHoloProgram();
  1800.  
  1801.     switch (hProg)
  1802.     {
  1803.     case -1:
  1804.         return;
  1805.  
  1806.     case 0:
  1807.         HoloIndex = 2;
  1808.         break;
  1809.  
  1810.     case 1:
  1811.         aFlag = 1;
  1812.         HoloIndex = 0;
  1813.         break;
  1814.  
  1815.     case 2:
  1816.         HoloIndex = 1;
  1817.         break;
  1818.  
  1819.     default:
  1820.         break;
  1821.     }
  1822.  
  1823.     ae->ObjList[3].Active = aFlag;
  1824.     ae->ObjList[4].Active = aFlag;
  1825.     ae->ObjList[9].Active = aFlag;
  1826.     ae->ObjList[11].Active = aFlag;
  1827.     ae->bMaps[HoloWalls[0]] = hMaps[HoloIndex];
  1828.     HoloSoundFlag = 1;
  1829.     AppPlaySound(SOUND_USER1);
  1830.     return;
  1831.     }
  1832.  
  1833. if (col != 11 || row != 33)
  1834.     HoloSoundFlag = 0;
  1835.  
  1836. }
  1837.  
  1838. /****************************************************************************
  1839. ** Our main entry point. There is alot of stuff here that should be       **
  1840. ** broken out into separate routines. My apologies for the mess!       **
  1841. **                                       **
  1842. ****************************************************************************/
  1843. int main(int argc,char *argv[])
  1844. {
  1845.     int        i,j,result,done;
  1846.     int        ViewNum,count;
  1847.     int        Spin,SpinAngle;
  1848.     int        mx,my,mbuttons;
  1849.     int        LostFlag,SkipTitle;
  1850.     int        NoMusic,MusicFlag;
  1851.     char    LastSeconds;
  1852.     UCHAR   far *oBuf;
  1853.     UCHAR   far *Video;
  1854.     UCHAR   OldColor,NewColor;
  1855.  
  1856.  
  1857. if (!InitializeMouse())
  1858.     {
  1859.     printf("Mouse required to run.\n");
  1860.     return(1);
  1861.     }
  1862.  
  1863.  
  1864. /* Disabled for now, should be in final version to not run if memory low */
  1865. #if 0
  1866. mx = (int)(farcoreleft() / 1024L);
  1867. if (mx < 450)
  1868.     {
  1869.     printf("Not enough memory to run. Current memory: %d\n",mx);
  1870.     return(1);
  1871.     }
  1872. #endif
  1873.  
  1874. /*------------------------------------------------------------------------*/
  1875. /* Get the memory for the interface structure. This can either be GLOBAL  */
  1876. /* or allocated.                              */
  1877. /*------------------------------------------------------------------------*/
  1878. ae = malloc(sizeof(ACKENG));
  1879. if (ae == NULL)
  1880.     {
  1881.     printf("Not enough memory to run.\n");
  1882.     return(1);
  1883.     }
  1884.  
  1885. memset(ae,0,sizeof(ACKENG));
  1886.  
  1887. if (LoadSmallFont())
  1888.     {
  1889.     printf("Not enough memory to run.\n");
  1890.     return(1);
  1891.     }
  1892.  
  1893. YouWON = 0;
  1894. BoltEnergy = 77;
  1895. Shooting = 0;
  1896. LostFlag = 0;
  1897. ViewNum = 0;
  1898. SoundDevice = DEV_SOUNDBLASTER;
  1899. MouseMode = 0;
  1900. SkipTitle = 0;
  1901. NoMusic = 0;
  1902. HoloSoundFlag = 0;
  1903. TextBGcolor = 7;
  1904. randomize();
  1905. MusicFlag = 1;
  1906.  
  1907. if (argc > 1)
  1908.     {
  1909.     for (i = 1; i < argc; i++)
  1910.     {
  1911.     if (!stricmp(argv[i],"-NS"))
  1912.         SoundDevice = DEV_NOSOUND;
  1913.  
  1914.     if (!stricmp(argv[i],"-M1"))
  1915.         MouseMode = 1;
  1916.  
  1917.     if (!stricmp(argv[i],"-SP"))
  1918.         SoundDevice = DEV_PCSPEAKER;
  1919.  
  1920.     if (!stricmp(argv[i],"-ST"))
  1921.         SkipTitle = 1;
  1922.  
  1923.     if (!stricmp(argv[i],"-NM"))
  1924.         NoMusic = 1;
  1925.     }
  1926.     }
  1927.  
  1928.  
  1929. AckSetVGAmode();
  1930. memset(colordat,0,768);
  1931. AckSetPalette(colordat);
  1932.  
  1933. if (!SkipTitle)
  1934.     ShowTitle();
  1935.  
  1936.  
  1937. #if USE_SOUND
  1938. if (AckSoundInitialize(SoundDevice))
  1939.     {
  1940.     AckSetTextmode();
  1941.     printf("Error initializing sound.\n");
  1942.     return(1);
  1943.     }
  1944. #endif
  1945.  
  1946.  
  1947. WallDelay = WALL_DELAY;
  1948.  
  1949. tmHours = START_HOURS;
  1950. tmMinutes = START_MINUTES;
  1951. LastSeconds = tmSeconds = START_SECONDS;
  1952. tmDelay = TIME_DELAY;
  1953.  
  1954.  
  1955. /*------------------------------------------------------------------------*/
  1956. /* Setup the structure for this particular application. The most important*/
  1957. /* fields before initializing are the viewport (or Win...) fields.      */
  1958. /*------------------------------------------------------------------------*/
  1959. ae->WinStartY = VP_STARTY;
  1960. ae->WinEndY = VP_ENDY;
  1961. ae->WinStartX = VP_STARTX;
  1962. ae->WinEndX = VP_ENDX;
  1963. ae->LightFlag = SHADING_ON;
  1964. ae->xPlayer = Views[ViewNum].xP;
  1965. ae->yPlayer = Views[ViewNum].yP;
  1966. ae->PlayerAngle = Views[ViewNum].Angle;
  1967. ae->TopColor = 28;
  1968. ae->BottomColor = 28;
  1969. ae->DoorSpeed = 4;
  1970. ae->NonSecretCode = 1;
  1971. strcpy(GridFile,"demomap.l01");
  1972.  
  1973. result = AckInitialize(ae);
  1974. if (result)
  1975.     {
  1976.     AckSetTextmode();
  1977.     printf("Initialize Error: %d\n",result);
  1978.  
  1979. #if USE_SOUND
  1980.     AckSoundShutdown();
  1981. #endif
  1982.  
  1983.     return(1);
  1984.     }
  1985.  
  1986. if (ReadMasterFile("demo.l01"))
  1987.     {
  1988.     AckSetTextmode();
  1989.     printf("Error reading ASCII file - ErrorCode = %d\n",ErrorCode);
  1990.     AckWrapUp(ae);
  1991.  
  1992. #if USE_SOUND
  1993.     AckSoundShutdown();
  1994. #endif
  1995.  
  1996.     return(1);
  1997.     }
  1998.  
  1999. result = AckReadMapFile(ae,GridFile);
  2000. if (result)
  2001.     {
  2002.     AckSetTextmode();
  2003.     printf("Error reading map file - ErrorCode = %d\n",result);
  2004.     AckWrapUp(ae);
  2005.  
  2006. #if USE_SOUND
  2007.     AckSoundShutdown();
  2008. #endif
  2009.  
  2010.     return(1);
  2011.     }
  2012.  
  2013. i = ae->MaxObjects;
  2014.  
  2015. nums[0] = 24;
  2016. nums[1] = 25;
  2017. nums[2] = 26;
  2018. nums[3] = 27;
  2019. ae->ObjList[MAX_OBJECTS-1].Dir = 10;
  2020. ae->ObjList[MAX_OBJECTS-1].Speed = 44;
  2021. AckCreateObject(ae,MAX_OBJECTS-1,4,nums);
  2022.  
  2023. ae->ObjList[MAX_OBJECTS-2].Dir = 10;
  2024. ae->ObjList[MAX_OBJECTS-2].Speed = 34;
  2025. AckCreateObject(ae,MAX_OBJECTS-2,4,nums);
  2026. ae->ObjList[MAX_OBJECTS-2].Dir = INT_ANGLE_270;
  2027. ae->ObjList[MAX_OBJECTS-2].x = 1184;
  2028. ae->ObjList[MAX_OBJECTS-2].y = 2976;
  2029. ae->ObjList[MAX_OBJECTS-2].Active = 1;
  2030.  
  2031. ae->MaxObjects = i;
  2032.  
  2033. ae->ObjList[35].Active = 0;
  2034. ae->ObjList[36].Active = 0;
  2035. ae->ObjList[37].Active = 0;
  2036.  
  2037. if (ae->BkgdBuffer)
  2038.     free(ae->BkgdBuffer);
  2039.  
  2040. ae->BkgdBuffer = AckReadiff("bitmaps\\back1.lbm");
  2041.  
  2042. if (ae->BkgdBuffer == NULL)
  2043.     {
  2044.     AckSetTextmode();
  2045.     printf("Not enough memory to load background.\n");
  2046.     AckWrapUp(ae);
  2047.  
  2048. #if USE_SOUND
  2049.     AckSoundShutdown();
  2050. #endif
  2051.  
  2052.     return(1);
  2053.     }
  2054.  
  2055. CompassBmp = AckReadiff("bitmaps\\compass.bbm");
  2056. if (CompassBmp == NULL)
  2057.     {
  2058.     AckSetTextmode();
  2059.     printf("Not enough memory to run.\n");
  2060.     AckWrapUp(ae);
  2061.  
  2062. #if USE_SOUND
  2063.     AckSoundShutdown();
  2064. #endif
  2065.  
  2066.     return(1);
  2067.     }
  2068.  
  2069. /*------------------------------------------------------------------------*/
  2070. /* Load our main screen which can also be used as an overlay          */
  2071. /*------------------------------------------------------------------------*/
  2072. oBuf = AckReadiff("bitmaps\\demo5.lbm");
  2073.  
  2074. if (oBuf == NULL)
  2075.     {
  2076.     AckSetTextmode();
  2077.     printf("Not enough memory to load overlay.\n");
  2078.     AckWrapUp(ae);
  2079.  
  2080. #if USE_SOUND
  2081.     AckSoundShutdown();
  2082. #endif
  2083.  
  2084.     return(1);
  2085.     }
  2086.  
  2087.  
  2088. #if USE_SOUND
  2089.     for (i = 0; i < SOUND_MAX_INDEX; i++)
  2090.     {
  2091.     if (SoundFiles[i] != NULL)
  2092.         AckLoadSound(i,SoundFiles[i]);
  2093.  
  2094.     }
  2095.  
  2096.     if (!NoMusic)
  2097.     AckPlayBackground(MusicFile);
  2098.     else
  2099.     MusicFlag = 0;
  2100.  
  2101. #endif
  2102.  
  2103. SetupAnimatedWalls();
  2104.  
  2105. Video = MK_FP(0xA000,0);
  2106.  
  2107. if (!SkipTitle)
  2108.     {
  2109.     AckFadeOut(0,255);
  2110.     memset(Video,0,64000);
  2111.     memset(ae->ScreenBuffer,0,768);
  2112.     AckSetPalette(ae->ScreenBuffer);
  2113.     }
  2114.  
  2115. AckLoadAndSetPalette(PalFile);
  2116.  
  2117. memset(ae->ScreenBuffer,0,768);
  2118. AckSetPalette(ae->ScreenBuffer);
  2119. /*------------------------------------------------------------------------*/
  2120. /* Just blit the main screen to the video (then fade later)          */
  2121. /*------------------------------------------------------------------------*/
  2122. memmove(Video,&oBuf[4],64000);
  2123.  
  2124. AckCreateOverlay(ae,&oBuf[4]);
  2125.  
  2126. ClearStatusLine(7);
  2127. ShowTime();
  2128. ShowLightbar();
  2129. if (!SkipTitle)
  2130.     ShowTextFile("intro.txt");
  2131.  
  2132. AckFadeIn(0,255,colordat);
  2133.  
  2134. if (!SkipTitle)
  2135.     {
  2136.     mbuttons = 0;
  2137.     while (!mbuttons)
  2138.     {
  2139.     mouse_read_cursor(&mbuttons,&my,&mx);
  2140.     if (kbhit())
  2141.         {
  2142.         getch();
  2143.         break;
  2144.         }
  2145.     }
  2146.     }
  2147.  
  2148. oldvec=getvect(KEYBD);
  2149. setvect(KEYBD,myInt);
  2150.  
  2151. OldTimer = getvect(0x1C);
  2152. setvect(0x1C,MyTimer);
  2153.  
  2154. /*------------------------------------------------------------------------*/
  2155. /* Use our main screen to create an overlay (we don't use it but this     */
  2156. /* is how an application would call the ACK engine)              */
  2157. /*------------------------------------------------------------------------*/
  2158.  
  2159. if (!MouseMode)
  2160.     mouse_show_cursor();
  2161.  
  2162. LastMouseIndex = MOUSE_ARROW;
  2163. SetMouseCursor(LastMouseIndex);
  2164. Spin = 0;
  2165. SpinAngle = 0;
  2166. done = 0;
  2167.  
  2168. /*------------------------------------------------------------------------*/
  2169. /* This is our main loop for processing until the player exits or the      */
  2170. /* game is completed (win or lose).                      */
  2171. /*------------------------------------------------------------------------*/
  2172. while (!done)
  2173.     {
  2174.     if (LastSeconds != tmSeconds)
  2175.     {
  2176.     ShowTime();
  2177.     LastSeconds = tmSeconds;
  2178.  
  2179.     if (tmHours == 0 && tmMinutes == 0 && tmSeconds == 0)
  2180.         {
  2181.         LostFlag = 1;
  2182.         break;
  2183.         }
  2184.     }
  2185.  
  2186. /*------------------------------------------------------------------------*/
  2187. /* Call the routine to change any wall tiles that need changing.      */
  2188. /*------------------------------------------------------------------------*/
  2189.     AnimateWalls();
  2190.  
  2191. /*------------------------------------------------------------------------*/
  2192. /* Update the location of the energy bolt if it was fired.          */
  2193. /*------------------------------------------------------------------------*/
  2194.     if (Shooting)
  2195.     UpdateBomb();
  2196.  
  2197.     UpdateWallBolt();
  2198.     UpdateSpaceMen();
  2199.  
  2200. /*------------------------------------------------------------------------*/
  2201. /* Call the engine to animate objects and then build the scene          */
  2202. /*------------------------------------------------------------------------*/
  2203.     AckCheckObjectMovement(ae);
  2204.     AckBuildView(ae);
  2205.     AckDrawOverlay(ae->ScreenBuffer,ae->OverlayBuffer);
  2206.     ShowCompass();
  2207.  
  2208.     i = 0;
  2209.     mouse_read_cursor(&mbuttons,&my,&mx);
  2210.     if (mx >= VP_STARTX-14 && mx <= VP_ENDX && my >= 0 && my <= VP_ENDY)
  2211.     {
  2212.     mouse_hide_cursor();
  2213.     i = 1;
  2214.     }
  2215.  
  2216.     if (InventoryFlag)
  2217.     ShowInventory();
  2218.  
  2219.     if (LockedFlag)
  2220.     {
  2221.     smWriteHUD(155,100,15,"LOCKED");
  2222.     LockedFlag = 0;
  2223.     }
  2224.  
  2225.     AckDisplayScreen(ae);
  2226.  
  2227.     if (!MouseMode)
  2228.     CheckMouseCursor(mx,my);
  2229.  
  2230.     if (i)
  2231.     mouse_show_cursor();
  2232.  
  2233. /*------------------------------------------------------------------------*/
  2234. /* Check open/close status of doors and play appropriate sounds          */
  2235. /*------------------------------------------------------------------------*/
  2236.     PlayDoorSounds();
  2237.  
  2238.     if (!BoltEnergy)
  2239.     {
  2240.     LostFlag = 1;
  2241.     break;
  2242.     }
  2243.  
  2244.     if (YouWON)
  2245.     break;
  2246.  
  2247. /*------------------------------------------------------------------------*/
  2248. /* Check to see if decompression has occurred in the station!          */
  2249. /*------------------------------------------------------------------------*/
  2250.     if (Decompress)
  2251.     {
  2252.     AppPlaySound(SOUND_HITWALL);    /* Change to decompress sound! */
  2253.     ShowColor(4);
  2254.     delay(500);
  2255.     ShowColor(64+4);
  2256.     delay(500);
  2257.     ShowColor(128+4);
  2258.     delay(500);
  2259.     ShowColor(192+4);
  2260.     delay(1000);
  2261.     LostFlag = 1;
  2262.     break;
  2263.     }
  2264.  
  2265.     if (Spin)
  2266.     {
  2267.     Spin >>= 1;
  2268.     ae->PlayerAngle += SpinAngle;
  2269.     if (ae->PlayerAngle >= INT_ANGLE_360)
  2270.         ae->PlayerAngle -= INT_ANGLE_360;
  2271.     if (ae->PlayerAngle < 0)
  2272.         ae->PlayerAngle += INT_ANGLE_360;
  2273.  
  2274.     }
  2275.  
  2276. /*------------------------------------------------------------------------*/
  2277. /* We'll allow two different modes of operation of the mouse. In mode 0   */
  2278. /* below a mouse cursor will be displayed and change shape depending on      */
  2279. /* what area of the viewport it is on. Mode 1 below will use the movement */
  2280. /* of the mouse to move the POV ala Wolf-3D. Only mode 0 will allow the      */
  2281. /* player to select icons for various actions.                  */
  2282. /*------------------------------------------------------------------------*/
  2283.     if (!MouseMode)
  2284.     {
  2285.     mouse_read_cursor(&mbuttons,&my,&mx);
  2286.     if (mbuttons & 1)
  2287.         {
  2288.  
  2289.         switch (LastMouseIndex)
  2290.         {
  2291.         case MOUSE_ARROW:
  2292.             break;
  2293.  
  2294.         case MOUSE_UPARROW:
  2295.             j = AckMovePOV(ae,ae->PlayerAngle,16);
  2296.  
  2297.             if (j == POV_XWALL || j == POV_YWALL)
  2298.             AppPlaySound(SOUND_HITWALL);
  2299.  
  2300.             if (j == POV_OBJECT)
  2301.             CheckOurObjects();
  2302.  
  2303.             j = AckCheckDoorOpen(ae->xPlayer,
  2304.                      ae->yPlayer,
  2305.                      ae->PlayerAngle,ae);
  2306.  
  2307.             /* Do something if door is locked */
  2308.             if (j & POV_DOORLOCKED)
  2309.             LockedFlag = 1;
  2310.  
  2311.             CheckPlayerSquare();
  2312.             break;
  2313.  
  2314.         case MOUSE_DNARROW:
  2315.             j = ae->PlayerAngle + INT_ANGLE_180;
  2316.             if (j >= INT_ANGLE_360)
  2317.             j -= INT_ANGLE_360;
  2318.  
  2319.             i = AckMovePOV(ae,j,16);
  2320.  
  2321.             if (i == POV_XWALL || i == POV_YWALL)
  2322.             AppPlaySound(SOUND_HITWALL);
  2323.  
  2324.             break;
  2325.  
  2326.         case MOUSE_LTARROW:
  2327.             SpinAngle = -INT_ANGLE_4;
  2328.             Spin = 1;
  2329.             break;
  2330.  
  2331.         case MOUSE_RTARROW:
  2332.             SpinAngle = INT_ANGLE_4;
  2333.             Spin = 1;
  2334.             break;
  2335.  
  2336.         default:
  2337.             break;
  2338.  
  2339.         }
  2340.  
  2341.  
  2342.  
  2343.     /*------------------------------------------------------------------------*/
  2344.     /* Now check to see if the mouse has hit one of the icons              */
  2345.     /*------------------------------------------------------------------------*/
  2346.         if (mx >= 10 && mx <= 131 && my >= 131 && my <= 139) /* Inventory */
  2347.         {
  2348.         mouse_released();
  2349.         InventoryFlag ^= 1;
  2350.         }
  2351.  
  2352.         if (mx >= 28 && mx <= 45 && my >= 142 && my <= 150) /* Map icon */
  2353.         {
  2354.         mouse_released();
  2355.         ShowOverhead();
  2356.         }
  2357.  
  2358.         if (mx >= 292 && mx <= 312 && my >= 131 && my <= 139) /* Help */
  2359.         {
  2360.         mouse_released();
  2361.         ShowInstructions();
  2362.         }
  2363.  
  2364.         if (mx >= 273 && mx <= 295 && my >= 142 && my <= 150) /* Drop */
  2365.         {
  2366.         mouse_released();
  2367.         DropObject();
  2368.         }
  2369.         }
  2370.     }
  2371.     else
  2372.     {
  2373.     CheckMouse(&mouse);
  2374.  
  2375.     if (mouse.mdx < 0)
  2376.         {
  2377.         Spin = -mouse.mdx;
  2378.         Spin >>= 3;
  2379.         SpinAngle = -INT_ANGLE_2 * Spin;
  2380.         Spin = 1;
  2381.         }
  2382.  
  2383.     if (mouse.mdx > 0)
  2384.         {
  2385.         Spin = mouse.mdx;
  2386.         Spin >>= 3;
  2387.         SpinAngle = INT_ANGLE_2 * Spin;
  2388.         Spin = 1;
  2389.         }
  2390.  
  2391.     if (mouse.mdy < 0)
  2392.         {
  2393.         i = -mouse.mdy;
  2394.         i >>= 2;
  2395.         i += 16;
  2396.         j = AckMovePOV(ae,ae->PlayerAngle,i);
  2397.  
  2398.         if (j == POV_XWALL || j == POV_YWALL)
  2399.         AppPlaySound(SOUND_HITWALL);
  2400.  
  2401.         if (j == POV_OBJECT)
  2402.         CheckOurObjects();
  2403.  
  2404.         j = AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,ae->PlayerAngle,ae);
  2405.         if (j & POV_DOORLOCKED)
  2406.         LockedFlag = 1;
  2407.  
  2408.         CheckPlayerSquare();
  2409.         }
  2410.  
  2411.     if (mouse.mdy > 0)
  2412.         {
  2413.         i = mouse.mdy;
  2414.         i >>= 2;
  2415.         i += 16;
  2416.         j = ae->PlayerAngle + INT_ANGLE_180;
  2417.         if (j >= INT_ANGLE_360)
  2418.         j -= INT_ANGLE_360;
  2419.  
  2420.         i = AckMovePOV(ae,j,i);
  2421.  
  2422.         if (i == POV_XWALL || i == POV_YWALL)
  2423.         AppPlaySound(SOUND_HITWALL);
  2424.         }
  2425.     }
  2426.  
  2427. /*------------------------------------------------------------------------*/
  2428. /* The right button or spacebar activates doors                  */
  2429. /*------------------------------------------------------------------------*/
  2430.     if ((mbuttons & 2) || (Keys[SPACEBAR_KEY]))
  2431.     {
  2432.     if (BoltEnergy)
  2433.         {
  2434.         i = MAX_OBJECTS-1;
  2435.         if (!ae->ObjList[i].Active)
  2436.         {
  2437.         AppPlaySound(SOUND_FIRING);
  2438.         ae->ObjList[i].x = ae->xPlayer;
  2439.         ae->ObjList[i].y = ae->yPlayer;
  2440.         ae->ObjList[i].Dir = ae->PlayerAngle;
  2441.         ae->ObjList[i].mPos = (ae->yPlayer & 0xFFC0) + (ae->xPlayer >> 6);
  2442.         ae->ObjList[i].VidRow = 160;
  2443.         ae->ObjList[i].Active = 1;
  2444.         Shooting = 1;
  2445.         BoltEnergy--;
  2446.         mouse_hide_cursor();
  2447.         ShowLightbar();
  2448.         mouse_show_cursor();
  2449.         }
  2450.         }
  2451.     }
  2452.  
  2453. /*------------------------------------------------------------------------*/
  2454. /* The keyboard is now checked.                          */
  2455. /*------------------------------------------------------------------------*/
  2456.     if(Keys[ESCAPE_KEY])
  2457.     break;
  2458.  
  2459.     if(Keys[RIGHT_ARROW_KEY])
  2460.     {
  2461.     Spin += 2;
  2462.     SpinAngle = INT_ANGLE_2 * Spin;
  2463.     }
  2464.  
  2465.     if(Keys[LEFT_ARROW_KEY])
  2466.     {
  2467.     Spin += 2;
  2468.     SpinAngle = -INT_ANGLE_2 * Spin;
  2469.     }
  2470.  
  2471.     if(Keys[UP_ARROW_KEY])
  2472.     {
  2473.     j = AckMovePOV(ae,ae->PlayerAngle,16);
  2474.  
  2475.     if (j == POV_XWALL || j == POV_YWALL)
  2476.         AppPlaySound(SOUND_HITWALL);
  2477.  
  2478.     if (j == POV_OBJECT)
  2479.         CheckOurObjects();
  2480.  
  2481.     j = AckCheckDoorOpen(ae->xPlayer,ae->yPlayer,ae->PlayerAngle,ae);
  2482.     if (j & POV_DOORLOCKED)
  2483.         LockedFlag = 1;
  2484.  
  2485.     CheckPlayerSquare();
  2486.     }
  2487.  
  2488.     if(Keys[DOWN_ARROW_KEY])
  2489.     {
  2490.     j = ae->PlayerAngle + INT_ANGLE_180;
  2491.     if (j >= INT_ANGLE_360)
  2492.         j -= INT_ANGLE_360;
  2493.  
  2494.     j = AckMovePOV(ae,j,16);
  2495.  
  2496.     if (j == POV_XWALL || j == POV_YWALL)
  2497.         AppPlaySound(SOUND_HITWALL);
  2498.  
  2499.     if (j == POV_OBJECT)
  2500.         CheckOurObjects();
  2501.  
  2502.     CheckPlayerSquare();
  2503.     }
  2504.  
  2505.     if (Keys[F1_KEY])
  2506.     {
  2507.     MouseMode ^= 1;
  2508.     while (Keys[F1_KEY]);
  2509.     if (!MouseMode)
  2510.         mouse_show_cursor();
  2511.     else
  2512.         mouse_hide_cursor();
  2513.     }
  2514.  
  2515.     if (Keys[LETTER_I_KEY])
  2516.     {
  2517.     InventoryFlag ^= 1;
  2518.     while (Keys[LETTER_I_KEY]);
  2519.     }
  2520.  
  2521.     if (Keys[LETTER_L_KEY])
  2522.     {
  2523.     ae->LightFlag ^= 1;
  2524.     }
  2525.  
  2526.     if (Keys[LETTER_M_KEY])
  2527.     {
  2528.     while (Keys[LETTER_M_KEY]);
  2529.     ShowOverhead();
  2530.     }
  2531.  
  2532.     if (Keys[LETTER_H_KEY])
  2533.     {
  2534.     while (Keys[LETTER_H_KEY]);
  2535.     ShowInstructions();
  2536.     }
  2537.  
  2538.     if (Keys[LETTER_D_KEY])
  2539.     {
  2540.     while (Keys[LETTER_D_KEY]);
  2541.     DropObject();
  2542.     }
  2543.  
  2544.     if (Keys[LETTER_S_KEY])
  2545.     {
  2546.     while (Keys[LETTER_S_KEY]);
  2547.  
  2548.     if (!NoMusic)
  2549.         {
  2550.         if (MusicFlag)
  2551.         {
  2552.         AckStopBackground();
  2553.         MusicFlag = 0;
  2554.         }
  2555.  
  2556.         }
  2557.     }
  2558.  
  2559.  
  2560. /*------------------------------------------------------------------------*/
  2561. /* This is some test code put in to try different players in the same      */
  2562. /* map. The number keys 1,2,3 activate 3 different players that all start */
  2563. /* out in the same place but at different angles. By moving a player and  */
  2564. /* then pressing 1,2,3 the new player can walk around and see the other      */
  2565. /* players as space-suited characters. Not all in yet, but its a start.      */
  2566. /*------------------------------------------------------------------------*/
  2567.     if (Keys[NUMBER_1_KEY] ||
  2568.     Keys[NUMBER_2_KEY] ||
  2569.     Keys[NUMBER_3_KEY])
  2570.     {
  2571.     Views[ViewNum].xP = ae->xPlayer;
  2572.     Views[ViewNum].yP = ae->yPlayer;
  2573.     Views[ViewNum].Angle = ae->PlayerAngle;
  2574.     ae->ObjList[ViewNum+5].x = ae->xPlayer;
  2575.     ae->ObjList[ViewNum+5].y = ae->yPlayer;
  2576.     ae->ObjList[ViewNum+5].Active = 1;
  2577.     j = (ae->ObjList[ViewNum+5].y & 0xFFC0) + (ae->ObjList[ViewNum+5].x >> 6);
  2578.  
  2579.     if (Keys[NUMBER_1_KEY])
  2580.         ViewNum = 0;
  2581.     if (Keys[NUMBER_2_KEY])
  2582.         ViewNum = 1;
  2583.     if (Keys[NUMBER_3_KEY])
  2584.         ViewNum = 2;
  2585.     ae->xPlayer = Views[ViewNum].xP;
  2586.     ae->yPlayer = Views[ViewNum].yP;
  2587.     ae->PlayerAngle = Views[ViewNum].Angle;
  2588.     ae->ObjList[ViewNum+5].x = ae->xPlayer;
  2589.     ae->ObjList[ViewNum+5].y = ae->yPlayer;
  2590.     ae->ObjList[ViewNum+5].Active = 0;
  2591.     j = (ae->ObjList[ViewNum+5].y & 0xFFC0) + (ae->ObjList[ViewNum+5].x >> 6);
  2592.     }
  2593.  
  2594.     }
  2595.  
  2596.  
  2597. setvect(KEYBD,oldvec);
  2598. setvect(0x1C,OldTimer);
  2599.  
  2600. /*------------------------------------------------------------------------*/
  2601. /* Here if time ran out, meaning the game has been lost.          */
  2602. /*------------------------------------------------------------------------*/
  2603. if (LostFlag)
  2604.     {
  2605.     YouWON = 0;
  2606.     if (!Decompress)
  2607.     {
  2608.     if (BoltEnergy)
  2609.         ShowTextFile("lost.txt");
  2610.     else
  2611.         ShowTextFile("lost1.txt");
  2612.  
  2613.     }
  2614.     else
  2615.     ShowTextFile("decomp.txt");
  2616.     AppPlaySound(SOUND_LOST);
  2617.     i = 3000;
  2618.     while (i)
  2619.     {
  2620.     if (kbhit())
  2621.         {
  2622.         getch();
  2623.         break;
  2624.         }
  2625.     delay(10);
  2626.     i--;
  2627.     }
  2628.     AckFadeOut(0,255);
  2629.     }
  2630.  
  2631. if (YouWON)
  2632.     {
  2633.     ShowTextFile("won.txt");
  2634.     AppPlaySound(SOUND_USER3);
  2635.     i = 3000;
  2636.     while (i)
  2637.     {
  2638.     if (kbhit())
  2639.         {
  2640.         getch();
  2641.         break;
  2642.         }
  2643.     delay(10);
  2644.     i--;
  2645.     }
  2646.     AckFadeOut(0,255);
  2647.     }
  2648.  
  2649. AckWrapUp(ae);
  2650.  
  2651. #if USE_SOUND
  2652. AckSoundShutdown();
  2653. #endif
  2654.  
  2655. AckSetTextmode();
  2656.  
  2657. return(0);
  2658. }
  2659.  
  2660.